//------------------------------------------------------------
//  Filename: eth_mac_cfgif.sv
//   
//  Author  : wlduan@gmail.com
//  Revise  : 2020-12-05 11:01
//  Description: 
//   
//  Copyright (C) 2014, YRBD, Inc. 					      
//  All Rights Reserved.                                       
//-------------------------------------------------------------
//
`timescale 1ns/1ps
 
module eth_mac_cfgif  #(
    parameter ADDR_WIDTH = 12,
    parameter DATA_WIDTH = 32,
    parameter N_PORTS    = 2
)
( 
    input logic   clk_i,  
    input logic   rstn_i,  

    BDU_IF.Slave  cpu_lint,
    BDU_IF.Master cpu_master[N_PORTS]
);      
//-------------------------------------------------------------
logic [N_PORTS-1:0] active_i;
logic [N_PORTS-1:0] active_q;
logic [N_PORTS-1:0] active_int;
//-------------------------------------------------------------
always_ff @(posedge clk_i,negedge rstn_i) begin
    if(rstn_i == 0)begin 
        active_q <= 'b0; 
    end 
    else begin 
        active_q <= active_int; 
    end 
end 
//-------------------------------------------------------------
enum logic[7:0] {IDLE,WAIT_GNT,WAIT_VLD} cs,ns;
//-------------------------------------------------------------
always_ff @(posedge clk_i,negedge rstn_i) begin
    if(rstn_i == 0)begin 
        cs <= IDLE; 
    end 
    else begin 
        cs <= ns; 
    end 
end 
//-------------------------------------------------------------
always_comb begin
    ns = cs;
    active_int = active_q;
    case(ns)
        IDLE: begin
            if(cpu_lint.req) begin
                active_int = active_i;
                if(cpu_lint.gnt) begin
                    ns = WAIT_VLD;
                end
                else begin
                    ns = WAIT_GNT;
                end
            end
        end
        WAIT_GNT: begin
            if(cpu_lint.gnt) begin 
                ns = WAIT_VLD;
            end
        end
        WAIT_VLD: begin
            if(cpu_lint.rvalid) begin
                if(cpu_lint.req) begin
                    active_int = active_i;
                    if(cpu_lint.gnt) begin
                        ns = WAIT_VLD;
                    end
                    else begin
                        ns = WAIT_GNT;
                    end
                end 
                else begin
                    ns = IDLE;
                end  
            end
        end
    endcase
end
//-------------------------------------------------------------
logic [N_PORTS -1:0]           ports_gnt;
logic [N_PORTS -1:0]           ports_rdy;
logic [N_PORTS -1:0]           ports_rvalid;
logic [N_PORTS*DATA_WIDTH-1:0] ports_rdata;
//-------------------------------------------------------------
generate 
    genvar i;
    for(i=0;i<N_PORTS;i++) begin
        assign ports_rdy[i] = ((((cs == IDLE)||(cs == WAIT_VLD))&active_i[i])||((cs == WAIT_GNT)&active_q[i]));
        always_comb begin
            cpu_master[i].addr  = 'b0;
            cpu_master[i].wdata = 'b0;
            cpu_master[i].we    = 'b0;
            if(active_q[i]) begin
                cpu_master[i].addr  = cpu_lint.addr  ; 
                cpu_master[i].wdata = cpu_lint.wdata ; 
                cpu_master[i].we    = cpu_lint.we    ; 
            end
        end        
        assign ports_gnt[i]                           = cpu_master[i].gnt;
        assign ports_rdata[DATA_WIDTH*i +:DATA_WIDTH] = cpu_master[i].rdata;
        assign ports_rvalid[i]                        = cpu_master[i].rvalid;
    end
endgenerate
//-------------------------------------------------------------
always_comb begin
    active_i = 0;
    active_i[(cpu_lint.addr[ADDR_WIDTH +: $clog2(N_PORTS)])] = 1'b1; 
end
//-------------------------------------------------------------
assign cpu_lint.gnt = |(ports_gnt&ports_rdy);
//-------------------------------------------------------------
always_comb begin
    cpu_lint.rdata  = 'b0;
    cpu_lint.rvalid = 'b0;
    for(reg[7:0] i=0;i<N_PORTS;i++) begin
        if((cs == WAIT_VLD)&active_q[i]) begin
            cpu_lint.rdata  = ports_rdata[DATA_WIDTH*i +:DATA_WIDTH];
            cpu_lint.rvalid = ports_rvalid[i];
        end
    end
end 
//-------------------------------------------------------------
      
endmodule
